package com.example.processor;

import com.example.annotation.MyAnnotation;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.*;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

/**
 *
 */
@SupportedAnnotationTypes("com.example.annotation.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyAnnotationProcessor extends AbstractProcessor {

    private Messager messager;//用来在编译期打log用
    private JavacTrees trees;//提供了待处理的抽象语法树
    private TreeMaker treeMaker;//封装了创建 AST 节点的一些方法
    private Names names;//提供了创建标识符的方法

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.messager = processingEnv.getMessager();
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
    }

    //如果设置了@SupportedAnnotationTypes
    //可以不重写这个方法
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(MyAnnotation.class);//过滤出标记的类
        //Element represents a program element such as a package, class, or method
        set.forEach(element -> {
            //对注解标记的类生成一个JCTree语法树
            JCTree jcTree = trees.getTree(element);
            jcTree.accept(new TreeTranslator() {
                //处理遍历语法树得到的类定义部分 JCClassDecl
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    //创建一个 jcVariableDeclList 保存类的成员变量
                    //遍历 jcTree 的所有成员(包括成员变量和成员函数和构造函数)
                    for (JCTree tree : jcClassDecl.defs) {
                        //过滤出其中的成员变量
                        if (tree.getKind().equals(Tree.Kind.VARIABLE)) {
                            JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) tree;
                            //打印
                            messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed");
                            //将 jcVariableDeclList 的所有变量转换成需要添加的 getter 方法
                            JCTree.JCMethodDecl jcMethodDecl = makeGetterMethodDecl(jcVariableDecl);
                            //并添加进 jcClassDecl 的成员中
                            jcClassDecl.defs = jcClassDecl.defs.prepend(jcMethodDecl);
                        }
                    }
                    super.visitClassDef(jcClassDecl);
                }
            });
        });
        return true;
    }


    private JCTree.JCMethodDecl makeGetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
        //创建 return this.var; 语句
        ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
        statements.append(
                treeMaker.Return(
                        treeMaker.Select(
                                treeMaker.Ident(
                                        names.fromString("this")
                                ),
                                jcVariableDecl.getName()
                        )
                )
        );

        //this.xxx = xxx;  setter方法中的赋值语句
        JCTree.JCStatement jcStatement = treeMaker.Exec(
                treeMaker.Assign(
                        treeMaker.Select(
                                treeMaker.Ident(
                                        names.fromString("this")
                                ),
                                jcVariableDecl.name),
                        treeMaker.Ident(jcVariableDecl.name))
        );

        //猜测应该是创建一个代码块的意思
        JCTree.JCBlock body = treeMaker.Block(0, statements.toList());
        return treeMaker.MethodDef(
                treeMaker.Modifiers(Flags.PUBLIC), //modifiers , 修饰方法的几种关键字
                getNewMethodName(jcVariableDecl.getName()), //方法名
                jcVariableDecl.vartype, //返回值类型
                List.nil(), //入参类型
                List.nil(), //入参变量描述
                List.nil(), //异常抛出列表
                body, //代码块
                null);
    }


//    //getter
//    private JCTree.JCMethodDecl makeGetterMethod(JCTree.JCVariableDecl jcVariableDecl) {
//        JCTree.JCModifiers jcModifiers = treeMaker.Modifiers(Flags.PUBLIC);//public
//        Name name = getterMethodName(jcVariableDecl);// 方法名getXxx
//        JCTree.JCExpression retrunType = jcVariableDecl.vartype;//方法返回类型
//        List<JCTree.JCTypeParameter> methodGenericParams = List.nil();//泛型参数列表
//        List<JCTree.JCVariableDecl> parameters = List.nil();//参数列表
//        List<JCTree.JCExpression> throwsClauses = List.nil();//异常抛出列表
//
//        //构建代码块
//        List<JCTree.JCStatement> jcStatementList = List.nil();
//        JCTree.JCStatement jcStatement = // retrun this.xxx
//                treeMaker.Return(treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.name));
//        jcStatementList = jcStatementList.append(jcStatement);
//        JCTree.JCBlock jcBlock = treeMaker.Block(0, jcStatementList);//构建代码块
//
//
//        JCTree.JCExpression defaultValue = null;//非自定义注解类中的方法，defaultValue为null
//
//        //最后构建getter方法
//        JCTree.JCMethodDecl jcMethodDecl = treeMaker.MethodDef(
//                jcModifiers, name, retrunType, methodGenericParams, parameters, throwsClauses, jcBlock, defaultValue);
//        return jcMethodDecl;
//    }
//
//    //setter
//    private JCTree.JCMethodDecl makeSetterMethod(JCTree.JCVariableDecl jcVariableDecl) {
//        JCTree.JCModifiers jcModifiers = treeMaker.Modifiers(Flags.PUBLIC);//public
//        JCTree.JCExpression retrunType = treeMaker.TypeIdent(TypeTag.VOID);//或 treeMaker.Type(new Type.JCVoidType())
//        Name name = setterMethodName(jcVariableDecl);// setXxx()
//        List<JCTree.JCVariableDecl> parameters = List.nil();//参数列表
//        JCTree.JCVariableDecl param = treeMaker.VarDef(
//                treeMaker.Modifiers(Flags.PARAMETER), jcVariableDecl.name, jcVariableDecl.vartype, null);
//        param.pos = jcVariableDecl.pos;//设置形参这一句不能少，不然会编译报错(java.lang.AssertionError: Value of x -1)
//        parameters = parameters.append(param);
//        //this.xxx = xxx;  setter方法中的赋值语句
//        JCTree.JCStatement jcStatement = treeMaker.Exec(treeMaker.Assign(
//                treeMaker.Select(treeMaker.Ident(names.fromString("this")), jcVariableDecl.name),
//                treeMaker.Ident(jcVariableDecl.name)));
//        List<JCTree.JCStatement> jcStatementList = List.nil();
//        jcStatementList = jcStatementList.append(jcStatement);
//        JCTree.JCBlock jcBlock = treeMaker.Block(0, jcStatementList);//代码块
//        List<JCTree.JCTypeParameter> methodGenericParams = List.nil();//泛型参数列表
//        List<JCTree.JCExpression> throwsClauses = List.nil();//异常抛出列表
//        JCTree.JCExpression defaultValue = null;
//        //最后构建setter方法
//        JCTree.JCMethodDecl jcMethodDecl = treeMaker.MethodDef(jcModifiers, name, retrunType, methodGenericParams, parameters, throwsClauses, jcBlock, defaultValue);
//        return jcMethodDecl;
//    }


    private Name getNewMethodName(Name name) {
        String s = name.toString();
        return names.fromString("get" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length()));

    }
}
